package com.android.allwinner.newaw360.media;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.PixelFormat;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceHolder;

import com.android.allwinner.aw360.AW360API;
import com.android.allwinner.newaw360.utils.CamParaUtil;
import com.android.allwinner.newaw360.utils.DisplayUtil;
import com.android.allwinner.newaw360.utils.LogUtil;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * Created by xiasj on 17-6-14.
 */

public class AW360MediaManager {
    private static final String TAG = AW360MediaManager.class.getSimpleName();
    public static final int MESSAGE_SERVICE_UNBIND = 0;
    private Camera mCamera;
    private boolean isPreviewing = false;
    private Context mContext;
    private AW360MediaService mAw360MediaService;
    private boolean isBindService;

    private AW360MediaManager() {
    }

    private static class SingletHolder {
        static final AW360MediaManager sInstance = new AW360MediaManager();
    }

    public static AW360MediaManager getInstance() {
        return SingletHolder.sInstance;
    }


    public boolean init(Context context) {

        mContext = context.getApplicationContext();
        if (mAw360MediaService == null) {
            bindService();
        }

        if (mCamera != null) {
            return true;
        }
        return openCamera();
    }

    public boolean isRecording(){
        return mAw360MediaService.isRecording();
    }


    public void release() {
        if(isBindService){
            unBindService();
            isBindService = false;
        }
        AW360API.getInstance().release();
        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
    }

    private void bindService() {
        if (mAw360MediaService == null) {
            Intent service = new Intent(mContext, AW360MediaService.class);
            try {
                isBindService = mContext.bindService(service, mMediaServiceConn,
                        Context.BIND_AUTO_CREATE);
            } catch (Exception e) {
                LogUtil.e(TAG, "---------have bind service");
            }
        }
    }

    private void unBindService() {
        if (mMediaServiceConn != null) {
            mContext.unbindService(mMediaServiceConn);
        }
        if (mAw360MediaService != null) {
            mAw360MediaService.stopSelf();
        }
    }

    private ServiceConnection mMediaServiceConn = new ServiceConnection() {
        public void onServiceConnected(ComponentName classname, IBinder obj) {
            LogUtil.i(TAG, "----onServiceConnected");
            mAw360MediaService = ((AW360MediaService.LocalBinder) obj)
                    .getService();
            if (isPreviewing) {
            }
        }

        public void onServiceDisconnected(ComponentName classname) {
            LogUtil.i(TAG, "----onServiceDisconnected");
            mAw360MediaService = null;
        }
    };


    private boolean openCamera() {
        LogUtil.i(TAG,"openCamera before");
        boolean result = true;
        try {
            Class<?> camera = Class.forName("android.hardware.Camera");
            Method open360 = camera.getMethod("open360");
            mCamera = (Camera) open360.invoke(null);
            LogUtil.i(TAG,"openCamera success");
            AW360API.getInstance().init(mContext, mCamera);
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "openCamera  ClassNotFoundException");
            result = false;
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "openCamera  NoSuchMethodException");
            result = false;
        } catch (IllegalAccessException e) {
            Log.e(TAG, "openCamera  IllegalAccessException");
            result = false;
        } catch (InvocationTargetException e) {
            Log.e(TAG, "openCamera  InvocationTargetException");
            result = false;
        } catch (RuntimeException e) {
            Log.e(TAG, "openCamera  RuntimeException");
            result = false;
        }

        if (mCamera == null) {
            result = false;
        }

        return result;
    }

    public boolean startPreview(SurfaceHolder surfaceHolder, boolean isFirstPreview) {
        LogUtil.i(TAG, "-----------startPreview");
        if (isPreviewing) {
            LogUtil.i(TAG, "----------startPreview---isPreview");
            return true;
        }
        if (mCamera == null) {
            LogUtil.i(TAG, "----------startPreview---camera = null-");
            return false;
        }

        try {
            LogUtil.e(TAG, "----------startPreview----startPreview");
            mCamera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            LogUtil.e(TAG, "----------startPreview----" + e.getMessage());
            return false;
        }


        Camera.Parameters mParams = mCamera.getParameters();
        mParams.setPictureFormat(PixelFormat.JPEG);

        Camera.Size previewSize = CamParaUtil.getInstance().getPropPreviewSize(
                mParams.getSupportedPreviewSizes(), DisplayUtil.getScreenRate(mContext), 800);
        mParams.setPreviewSize(previewSize.width, previewSize.height);

        mCamera.setDisplayOrientation(90);

        List<String> focusModes = mParams.getSupportedFocusModes();
        if (focusModes.contains("continuous-video")) {
            mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }
        mCamera.setParameters(mParams);

        try {
            mCamera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            LogUtil.e(TAG, "startPreview  ---" + e.getMessage());
            return false;
        }
        if (isFirstPreview) {
            mCamera.startPreview();
        } else {
            startRender(surfaceHolder);
        }

        isPreviewing = true;
        return isPreviewing;
    }

    public boolean startPreview(SurfaceTexture surface) {
        LogUtil.i(TAG, "----------startPreview----");
        if (isPreviewing) {
            LogUtil.i(TAG, "----------mCamera startPreview---isPreviewing -true-");
            return true;
        }

        if (mCamera == null) {
            LogUtil.i(TAG, "----------mCamera startPreview---camera = null-");
            return false;
        }

        try {
            mCamera.setPreviewTexture(surface);
            LogUtil.i(TAG, "----------mCamera startPreview----");
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e(TAG, "----startPreview---" + e.getMessage());
            return false;
        }
        isPreviewing = true;
        return true;
    }


    public void stopPreview(boolean isExit) {
        if (!isPreviewing) {
            return;
        }
        isPreviewing = false;
        if (mCamera == null) {
            return;
        }
        if (isExit) {
            mCamera.stopPreview();
        } else {
            stopRender();
        }
    }

    public void startRender(SurfaceHolder surface) {
        try {
            mCamera.setPreviewDisplay(surface);
            //反射调用startRender
            Class<?> camera = Class.forName("android.hardware.Camera");
            Method startRender = camera.getMethod("startRender");
            startRender.invoke(mCamera);
        } catch (IOException e) {
            LogUtil.e(TAG, "startRender() IOException");
        } catch (NoSuchMethodException e) {
            LogUtil.e(TAG, "No startRender() method");
        } catch (IllegalAccessException e) {
            LogUtil.e(TAG, "startRender() IllegalAccessException");
        } catch (InvocationTargetException e) {
            LogUtil.e(TAG, "startRender() InvocationTargetException");
        } catch (ClassNotFoundException e) {
            LogUtil.e(TAG, "startRender() ClassNotFoundException");
        }
    }

    public void stopRender() {
        //反射调用stopRender
        try {
            Class<?> camera = Class.forName("android.hardware.Camera");
            Method startRender = camera.getMethod("stopRender");
            startRender.invoke(mCamera);
        } catch (NoSuchMethodException e) {
            LogUtil.e(TAG, "No stopRender() method");
        } catch (InvocationTargetException e) {
            LogUtil.e(TAG, "stopRender() InvocationTargetException");
        } catch (IllegalAccessException e) {
            LogUtil.e(TAG, "stopRender() IllegalAccessException");
        } catch (ClassNotFoundException e) {
            LogUtil.e(TAG, "stopRender() ClassNotFoundException");
        }
    }

    public void startRecorder(final Handler handler) {
        if (mAw360MediaService != null) {
            mAw360MediaService.startRecorder(mCamera, handler);
        } else {
            bindService();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    startRecorder(handler);
                }
            }, 500);
        }
    }

    public void stopRecorder() {
        if (mAw360MediaService != null) {
            mAw360MediaService.stopRecorder();
        }
    }
}
